'use strict';
$(function(){
    var URLS = {
        iBg: 'demo.jpg'
    };
    var jqShow = $('.js-show'),
        jqFileinput = $('.js-fileinput'),
        jqColorInput = $('.js-color');
    var oCanvasApi;
    var fGetPoints = function(){
        var aPoints = oCanvasApi.getPoints(),
            str = aPoints.join(',');
        $.showAlert(str);
    };
    var fFileInputChange = function(){
        var file = this.files[0];
        var reader = new FileReader();
        reader.onload = function () {
            oCanvasApi.reset({
                img: reader.result
            })
        };
        reader.readAsDataURL(file);
        $(this).val('');

    };
    var fTBtnsClick = function(){
        var jqCur = $(this);
        switch(jqCur.attr('data-type')){
            case 'getImage':
                jqFileinput.click();
                break;
            case 'getPoints':
                fGetPoints();
                break;
            case 'reset':
                oCanvasApi.reset();
                break;
            case 'changeColor':
                oCanvasApi.changeColor(jqColorInput.val());
                break;
        }
    };
    var fMouseMove = function(loc){
        jqShow.html('x: '+ loc.x +'<br/> y: ' + loc.y);
    };
    /** =============== **/
    $('.js-btns').on('click','.btn',fTBtnsClick);
    jqFileinput.on('change',fFileInputChange);
    oCanvasApi = $('.js-canvas').initCanvas({
        img: URLS.iBg,
        //color: '#ff0000',
        mouseMove: fMouseMove
    });
});


$.fn.initCanvas = function(opts){
    opts = $.extend({
        //img: '',
        //color: '#000',
        //mouseMove: $.noop()
    }, opts);

    var POINT_RADIUS = 4;

    var jqEl = $(this),
        dCanvas,
        oContext,
        jqContextmenu,
        api,
        oZero={x:0,y:0},// 记录图片左上角的坐标
        nScale = 1,
        oImg,// 背景图片
        oImgSize,
        nId = 0,
        oDragging,
        bDragImage = false,
        aPoints;// 坐标点数组

    // 将鼠标坐标 转化为canvas中的坐标
    var windowToCanvas = function(x, y){
        var oBox = dCanvas.getBoundingClientRect();
        return {
            x: parseInt((x - oBox.left) * dCanvas.width / oBox.width / nScale),
            y: parseInt((y - oBox.top) * dCanvas.height / oBox.height / nScale)
        };
    };

    var Point = function(loc){
        $.extend(this,{
            x: loc.x - oZero.x,
            y: loc.y - oZero.y
        });
        this.id = nId++;
    };
    Point.prototype = {
        getData: function(){
            var oCur = this;
            return oCur.x+ ',' +oCur.y;
        },
        draw: function(){
            var oCur = this,
                nX = oCur.x*nScale,
                nY = oCur.y*nScale;
            oContext.beginPath();
            oContext.arc(nX,nY,POINT_RADIUS,0,Math.PI*2);
            oContext.stroke();
            oContext.beginPath();
            oContext.arc(nX,nY,2,0,Math.PI*2);
            oContext.fill();
        },
        locInPoint: function(loc){
            var oCur = this,
                nX = oCur.x + oZero.x,
                nY = oCur.y + oZero.y;
            oContext.beginPath();
            oContext.arc(nX,nY,POINT_RADIUS,0,Math.PI*2);
            return oContext.isPointInPath(loc.x, loc.y);
        }
    };

    var fDrawBackground = function(){
        var jqImg;
        oImg = new Image();
        jqImg = $(oImg);
        oImg.onload = function(){
            jqEl.append(jqImg);
            oImgSize = {
                width:jqImg.width(),
                height:jqImg.height()
            };
            jqImg.remove();
            oZero = {
                x: parseInt((dCanvas.width-oImgSize.width)/2),
                y: parseInt((dCanvas.height-oImgSize.height)/2)
            };
            fDraw();
        };
        if(opts.img){
            oImg.src = opts.img;
        }
    };

    var fDraw = function(){
        var oldPoint;
        oContext.clearRect(0,0,dCanvas.width,dCanvas.height);
        oContext.save();
        oContext.translate(oZero.x*nScale,oZero.y*nScale);
        oContext.drawImage(oImg,0,0,oImgSize.width*nScale,oImgSize.height*nScale);
        aPoints.forEach(function(point,index){
            point.draw();
            if(index){
                oContext.beginPath();
                oContext.moveTo(oldPoint.x*nScale,oldPoint.y*nScale);
                oContext.lineTo(point.x*nScale,point.y*nScale);
                oContext.stroke();
            }
            oldPoint = point;
        });
        oContext.restore();
    };

    // 判断坐标是否在图形内，如果是则返回该图形，否则返回null;
    var fLocInPoint = function(loc){
        var i, point;
        for(i = aPoints.length - 1; i >= 0; i--){
            point = aPoints[i];
            if(point.locInPoint(loc)){
                return point;
            }
        }
        return null;
    };
    // 添加鼠标按下事件监听
    var fOnMouseDown = function(e){
        e.preventDefault(); // prevent cursor change
        jqContextmenu.hide();
        if(e.button === 0 && opts.img){// 只有左键按下的时候 且 有背景图片的时候触发
            var loc = windowToCanvas(e.clientX, e.clientY);
            if(bDragImage){
                oDragging = {
                    x: loc.x - oZero.x,
                    y: loc.y - oZero.y
                };
            }else{
                oDragging = fLocInPoint(loc);
                if(!oDragging){
                    oDragging = new Point({
                        x: loc.x,
                        y: loc.y
                    });
                    aPoints.push(oDragging);
                    fDraw();
                }

            }
        }
    };

    // 监听鼠标移动事件
    var fOnMouseMove = function(e){
        e.preventDefault(); // prevent cursor change
        var loc = windowToCanvas(e.clientX, e.clientY);
        opts.mouseMove && opts.mouseMove({
            x:loc.x - oZero.x,
            y:loc.y - oZero.y
        });
        if(bDragImage && oDragging){
            oZero.x = loc.x - oDragging.x;
            oZero.y = loc.y - oDragging.y;
            fDraw();
        }else if(oDragging){
            oDragging.x = loc.x - oZero.x;
            oDragging.y = loc.y - oZero.y;
            fDraw();
        }
    };

    // 添加鼠标松开事件监听
    var fOnMouseUp = function(e){
        e.preventDefault(); // prevent cursor change
        oDragging = null;
    };

    // 添加canvas右键菜单监听
    var fOnContextmenu = function(e){
        e.preventDefault(); // prevent cursor change
        var loc = windowToCanvas(e.clientX, e.clientY),
            oCurPoint = fLocInPoint(loc),
            str = '';
        jqContextmenu.off('click');
        if(oCurPoint){
            str += '<li>删除点</li>';
            jqContextmenu.html(str);
            jqContextmenu.on('click','li',function(){
                jqContextmenu.hide();
                for(var i = 0, point; i < aPoints.length; i++){
                    point = aPoints[i];
                    if(point.id == oCurPoint.id){
                        aPoints.splice(i, 1);
                    }
                }
                fDraw();
            });
            jqContextmenu.css({// 显示右键菜单
                display: 'block',
                left: loc.x*nScale + "px",
                top: loc.y*nScale + "px"
            });
        }
    };

    // 绑定键盘按下事件
    var fOnKeyDown = function(e){
        switch(e.keyCode){
            case 32:// 按下空格拖拽canvas
                bDragImage = true;
                dCanvas.style.cursor = 'pointer';
                e.preventDefault(); // prevent cursor change
                break;
        }
    };
    // 绑定键盘弹起事件
    var fOnKeyUp = function(e){
        switch(e.keyCode){
            case 32:// 空格
                bDragImage = false;
                dCanvas.style.cursor = 'default';
                e.preventDefault(); // prevent cursor change
                break;
        }
    };
    // 添加鼠标滚轮事件
    var fOnMouseWheel = function(e){
        var loc = windowToCanvas(e.clientX, e.clientY),
            nOldScale = nScale;
        if(e.wheelDelta>0){
            nScale += 1;
        }else if(nScale>1){
            nScale -= 1;
        }else{
            return;
        }
         oZero = {
            x: parseInt((nOldScale/nScale-1)*loc.x) + oZero.x,
            y: parseInt((nOldScale/nScale-1)*loc.y) + oZero.y
        };
        opts.mouseMove && opts.mouseMove({
            x:loc.x - oZero.x,
            y:loc.y - oZero.y
        });
        fDraw();
    };

    var fBindEvents = function(){
        dCanvas.onmousedown = fOnMouseDown;// 添加鼠标按下事件监听
        dCanvas.onmousemove = fOnMouseMove;// 监听鼠标移动事件
        dCanvas.onmouseup = fOnMouseUp;// 添加鼠标松开事件监听
        dCanvas.oncontextmenu = fOnContextmenu;// 添加canvas右键菜单监听
        document.onkeydown = fOnKeyDown;// 添加键盘按下事件监听
        document.onkeyup = fOnKeyUp;// 添加键盘按下事件监听
        jqContextmenu[0].oncontextmenu = function(e){// 去除弹出框的右键点击事件
            return false;
        };
        dCanvas.onmousewheel = fOnMouseWheel;// 添加鼠标滚轮事件
    };

    var fInit = function(){
        dCanvas = $('<canvas class="canvas"></canvas>')[0];// canvas对象
        oContext = dCanvas.getContext('2d');// canvas中创建2d图像
        dCanvas.width = jqEl.width();
        dCanvas.style.width = dCanvas.width + 'px';
        dCanvas.height = jqEl.height();
        dCanvas.style.height = dCanvas.height + 'px';
        jqContextmenu = $('<ul class="canvas-contextmenu unselectable"></ul>');// 右键菜单
        jqEl.append(dCanvas,jqContextmenu);

        fBindEvents();
        fReset();
    };

    var fReset = function(data){
        if(data){
            $.extend(opts,data)
        }
        aPoints = [];
        nScale = 1;
        oContext.strokeStyle = oContext.fillStyle = opts.color;
        fDrawBackground();
    };

    var fGetPoints = function(){
        var rst = [];
        aPoints.forEach(function(point){
            rst.push(point.getData());
        });
        return rst;
    };

    var fChangeColor = function(sColor){// 不清空点
        oContext.strokeStyle = oContext.fillStyle = opts.color = sColor;
        fDraw();
    };
    /** =============== **/
    api = {
        getPoints: fGetPoints,
        changeColor: fChangeColor,
        reset: fReset
    };
    fInit();
    return api;
};